package com.googlecode.ascrblr.cli;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

import org.apache.commons.io.FilenameUtils;
import org.farng.mp3.MP3File;
import org.farng.mp3.TagException;

import com.googlecode.ascrblr.api.scrobbler.AudioscrobblerService;
import com.googlecode.ascrblr.api.scrobbler.TrackInfo;
import com.googlecode.ascrblr.api.scrobbler.TrackInfoFactory;
import com.googlecode.ascrblr.api.scrobbler.TrackInfoList;
import com.googlecode.ascrblr.api.util.ServiceException;
import com.googlecode.ascrblr.cli.conf.CommandLineOption;
import com.googlecode.ascrblr.cli.conf.ConfigurationBean;
import com.googlecode.ascrblr.cli.conf.ConfigurationException;
import com.googlecode.ascrblr.cli.conf.ConfigurationFactory;

/**
 * The Class ScrobblerCLI.
 */
public class ScrobblerCLI {

	private ConfigurationBean config = null;

	private static final Logger logger = Logger
			.getLogger(ScrobblerCLI.class.getName());

	private AudioscrobblerService service = new AudioscrobblerService();
	private static final TrackInfoFactory TF = TrackInfoFactory.getInstance();

	/**
	 * @param args
	 * @throws ConfigurationException
	 */
	public ScrobblerCLI(String[] args) throws ConfigurationException {
		super();

		if (args == null || args.length == 0) {
			throw new IllegalArgumentException("args must not be empty");
		}

		config = ConfigurationFactory.getInstance().createConfiguration(args);

	}

	/**
	 * The main method.
	 * 
	 * @param args
	 *            the args
	 */
	public static void main(String[] args) {
		// args = new String[] { "--user=janhoo", "-r", "--password=7thson",
		// "d:/tmp/mp3"};

		ScrobblerCLI scrobblerCLI = null;

		try {
			scrobblerCLI = new ScrobblerCLI(args);
			if (scrobblerCLI.config.isShowHelp()) {
				System.out.println(CommandLineOption.getUsage());
				System.exit(0);
			}
		} catch (ConfigurationException e) {
			logger.severe(e.getMessage());
			System.err.println(e.getMessage());
			System.exit(1);
		}

		try {
			scrobblerCLI.run();
		} catch (ServiceException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	@Override
	public String toString() {
		return new StringBuffer().append("ScrobblerCLI {").append(
				"config=" + config).append("}").toString();
	}

	/**
	 * Run.
	 * 
	 * @throws ServiceException
	 */
	public void run() throws ServiceException {

		List<File> fileList = getFiles(config.getArguments());
		List<MP3File> mp3Files = TrackInfoFactory.getMp3Files(fileList);

		try {
			service.setCredentials(config.getUser(), config.getPassword());
			service.setConnectionTimeout(1000);
			service.setReadTimeout(1000);
		} catch (ServiceException e) {
			throw e;
		}

		if (mp3Files.size() == 1) {
			handleSingle(mp3Files.get(0));
		} else {
			handleMulti(mp3Files);
		}

	}

	/**
	 * Handle single.
	 * 
	 * @param mp3File
	 *            the mp3 file
	 */
	private void handleSingle(MP3File mp3File) {
		TrackInfo trackInfo = null;
		try {
			trackInfo = TF.create(mp3File);
		} catch (TagException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		try {
			service.submit(trackInfo);
		} catch (ServiceException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * Handle multi.
	 * 
	 * @param mp3Files
	 *            the mp3 files
	 */
	private void handleMulti(List<MP3File> mp3Files) {
		TrackInfoList trackInfoList = TF.create(mp3Files);

		for (TrackInfo trackInfo : trackInfoList.getTrackInfoList()) {

			try {
				service.submit(trackInfo);
			} catch (ServiceException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

		return;
	}

	/**
	 * Gets the files.
	 * 
	 * @param paths
	 *            the paths
	 * 
	 * @return the files
	 */
	public List<File> getFiles(ArrayList<String> paths) {
		List<File> result = new ArrayList<File>();

		for (String path : paths) {
			File file = new File(path);

			if (!file.exists() || !file.canRead()) {
				continue;
			}

			if (file.isDirectory()) {
				if (config.isRecursive()) {
					readDir(file, result);
				} else {
					continue;
				}
			}

			if ("mp3".equalsIgnoreCase(FilenameUtils.getExtension(file
					.getName()))) {
				result.add(file);
			}

		}

		return result;
	}

	/**
	 * Read dir.
	 * 
	 * @param dir
	 *            the dir
	 * @param result
	 *            the result
	 * 
	 * @return the list< file>
	 */
	private List<File> readDir(File dir, List<File> result) {
		if (result == null) {
			result = new ArrayList<File>();
		}
		if (dir == null || !dir.isDirectory() || !dir.canRead()) {
			return result;
		}

		final FileFilter FILTER_DIR = new FileFilter() {
			public boolean accept(File file) {
				return (file != null && file.isDirectory() && file.canRead());
			}
		};

		final FileFilter FILTER_MP3 = new FileFilter() {
			public boolean accept(File file) {
				return (file != null && file.isFile() && file.canRead() && "mp3"
						.equals(FilenameUtils.getExtension(file.getName())));
			}
		};

		List<File> subDirs = Arrays.asList(dir.listFiles(FILTER_DIR));

		List<File> mp3s = Arrays.asList(dir.listFiles(FILTER_MP3));

		if (mp3s != null && mp3s.size() > 0) {
			result.addAll(mp3s);
		}

		for (Iterator<File> it = subDirs.iterator(); it.hasNext();) {
			readDir(it.next(), result);
		}

		return result;
	}

}
